#include <gtest/gtest.h>

// IOpenable --> Openable , Openable<std::error_code>
//					 --> Reopenable
//					 --> AutoOpenable TODO:
//					 --> RefCountOpenable TODO:


#include "helper/resource/Openable.h"

template<typename T>
using IOpenable = typename helper::resource::IOpenable<T>;

template<typename T>
using Openable = typename helper::resource::Openable<T>;

class Resource : public Openable<bool> {
protected:
	Openable<bool>::return_type _open() override {
		return true;
	}
  Openable<bool>::return_type _close() override {
		return true;
	}
};


TEST(OpenableTest, test){

	ASSERT_FALSE(bool());

	IOpenable<bool> * re = new Resource();
	ASSERT_FALSE(re->isOpened());

	ASSERT_TRUE(re->open());
	ASSERT_TRUE(re->isOpened());

	ASSERT_FALSE(re->open()); // re-open -> false

	ASSERT_TRUE(re->close());

	ASSERT_FALSE(re->close()); // re-close -> false

	ASSERT_FALSE(re->isOpened());

	delete re;
}


class EcResource : public Openable<std::error_code> {
protected:
	Openable<std::error_code>::return_type _open() override {
		return std::error_code();
	}
  Openable<std::error_code>::return_type _close() override {
		return std::error_code();
	}
};

TEST(ErrorCodeOpenableTest, test){
	IOpenable<std::error_code> * re = new EcResource();
	ASSERT_FALSE(re->isOpened());

	ASSERT_EQ(std::error_code(), re->open());
	ASSERT_TRUE(re->isOpened());

	ASSERT_NE(std::error_code(), re->open()); //re-open != ec(0)

	ASSERT_EQ(std::error_code(), re->close());

	ASSERT_FALSE(re->isOpened());

	ASSERT_NE(std::error_code(), re->close()); //re-close != ec(0)

	delete re;
}


#include "helper/resource/Reopenable.h"

template<typename T>
using Reopenable = typename helper::resource::Reopenable<T>;

class ReopenResource : public Reopenable<bool> {
protected:
	Openable<bool>::return_type _open() override {
		return true;
	}
  Openable<bool>::return_type _close() override {
		return true;
	}
};


TEST(ReopenableTest, test){

	ASSERT_FALSE(bool());

	IOpenable<bool> * re = new ReopenResource();
	ASSERT_FALSE(re->isOpened());

	ASSERT_TRUE(re->open());
	ASSERT_TRUE(re->isOpened());

	ASSERT_TRUE(re->open()); // re-open -> true
	ASSERT_TRUE(re->open()); // re-open -> true
	ASSERT_TRUE(re->open()); // re-open -> true
	ASSERT_TRUE(re->open()); // re-open -> true

	ASSERT_TRUE(re->close());

	ASSERT_TRUE(re->close()); // re-close -> true
	ASSERT_TRUE(re->close()); // re-close -> true
	ASSERT_TRUE(re->close()); // re-close -> true
	ASSERT_TRUE(re->close()); // re-close -> true
	ASSERT_TRUE(re->close()); // re-close -> true
	ASSERT_TRUE(re->close()); // re-close -> true

	ASSERT_FALSE(re->isOpened());

	delete re;
}


class EcReopenResource : public Reopenable<std::error_code> {
protected:
	Reopenable<std::error_code>::return_type _open() override {
		return std::error_code();
	}
  Reopenable<std::error_code>::return_type _close() override {
		return std::error_code();
	}
};

TEST(ErrorCodeReopenableTest, test){
	IOpenable<std::error_code> * re = new EcReopenResource();
	ASSERT_FALSE(re->isOpened());

	ASSERT_EQ(std::error_code(), re->open());
	ASSERT_TRUE(re->isOpened());

	ASSERT_EQ(std::error_code(), re->open()); //re-open == ec(0)

	ASSERT_EQ(std::error_code(), re->close());

	ASSERT_FALSE(re->isOpened());

	ASSERT_EQ(std::error_code(), re->close()); // re-close ==  ec(0)

	delete re;
}

/*  
class AutoOpenResource : public Openable<bool> {
public:
	AutoOpenResource(){
		open();
	}
	~AutoOpenResource() override{
		ASSERT_TRUE(close());
	}
protected:
	Openable<bool>::return_type _open() {
		
		return true;
	}
  Openable<bool>::return_type _close() {
		return true;
	}
};
TEST(OpenableTest, test){
	AutoOpenResource ao;
	ASSERT_TRUE(ao.isOpened());

	ASSERT_TRUE(ao.close());
}*/
